package com.sudo.service.impl;

import com.fasterxml.jackson.databind.util.BeanUtil;
import com.github.pagehelper.PageHelper;
import com.sudo.common.enums.SysStatus;
import com.sudo.common.enums.UserParams;
import com.sudo.common.utils.DateUtil;
import com.sudo.common.utils.MD5Utils;
import com.sudo.common.utils.PagedGridResult;
import com.sudo.common.utils.RedisOperator;
import com.sudo.mapper.my.*;
import com.sudo.pojo.SysRole;
import com.sudo.pojo.SysUser;
import com.sudo.pojo.SysUserRole;
import com.sudo.pojo.bo.SimpleUserBO;
import com.sudo.pojo.bo.SysUserBasicInfoBO;
import com.sudo.pojo.bo.SysUserReBO;
import com.sudo.pojo.vo.SysSimpleUserVO;
import com.sudo.pojo.vo.SysUserMainVO;
import com.sudo.pojo.vo.SysUserOnlineVO;
import com.sudo.pojo.vo.SysUserReVO;
import com.sudo.service.BaseService;
import com.sudo.service.SysRoleService;
import com.sudo.service.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static org.springframework.data.repository.init.ResourceReader.Type.JSON;

@Service
public class SysUserServiceImpl extends BaseService implements SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysUserMapperCustom sysUserMapperCustom;

    @Autowired
    private RedisOperator redisOperator;
    /**
     * 用户登录
     * @param mailOrUsername 账号
     * @param pwd 密码
     * @return SysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS ,rollbackFor = Exception.class)
    @Override
    public SysUser sysUserLoginByMailOrUsername(String mailOrUsername, String pwd) {
        String md5Pwd = null;
        try {
            md5Pwd = MD5Utils.getMD5Str(pwd);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //通过用户名、密码查询用户
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username",mailOrUsername);
        criteria.andEqualTo("password", md5Pwd);
        SysUser sysUser = sysUserMapper.selectOneByExample(example);
        if (null != sysUser){
            return sysUser;
        }

        //通过邮箱查询、密码用户
        Example.Criteria criteria1 = example.createCriteria();
        criteria1.andEqualTo("mail",mailOrUsername);
        criteria1.andEqualTo("password", md5Pwd);
        SysUser sysUser1 = sysUserMapper.selectOneByExample(example);
        if (null != sysUser1){
            return sysUser1;
        }
        return null;
    }

    /**
     * 通过邮箱或用户名判断账户是否存在
     * @param mailOrUsername 账户
     * @return boolean
     */
    @Transactional(propagation = Propagation.SUPPORTS ,rollbackFor = Exception.class)
    @Override
    public boolean queryMailOrUsernameIsExist(String mailOrUsername) {

        SysUser sysUser = getSysUserByUsername(mailOrUsername);
        SysUser sysUser1 = getSysUserByMail(mailOrUsername);

        if (sysUser == null && sysUser1 == null) {
            return false;
        }
        return true;
    }

    /**
     * 通过用户名获取用户信息
     * @param username 用户名
     * @return sysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysUser getSysUserByUsername(String username) {

        Example example = new Example(SysUser.class);
        example.excludeProperties("password");
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username",username);
        return sysUserMapper.selectOneByExample(example);
    }

    /**
     * 通过邮件获取用户信息
     * @param mail 邮件
     * @return SysUser
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public SysUser getSysUserByMail(String mail) {

        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("mail",mail);
        return sysUserMapper.selectOneByExample(example);
    }


    /**
     * 分页获取用户信息，查询条件 = 用户名，昵称，邮箱
     * @param page 当前页
     * @param pageSize 每页行数
     * @param usernameOrNick 参数（用户名，昵称，邮箱）
     * @return pageResult
     */
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    @Override
    public PagedGridResult queryAllSysUserMainInfoByPage(Integer page , Integer pageSize , String usernameOrNick) {
        PageHelper.startPage(page, pageSize);
        List<SysUserMainVO> sysUserList = sysUserMapperCustom.getAllSysUserMainInfo(usernameOrNick);

        return setterPagedGrid(sysUserList ,page);
    }

    /**
     * 通过用户名获取用户信息和其对应的角色
     * @param username 用户名
     * @return sysUserReVO
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    public SysUserReVO getSysUserAndRoleByUsername(String username) {
        return sysUserMapperCustom.getSysUserAndRoleByUsername(username);
    }

    /**
     * 新增用户，包含角色code
     * @param simpleUserBO 参数（用户信息，角色code）
     * @param sessionUser 当前session用户
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int addUser(SimpleUserBO simpleUserBO , String sessionUser) {
        //1.添加用户信息
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(simpleUserBO, sysUser,"roleCode");
        sysUser.setCreateBy(sessionUser);
        String dateTime = DateUtil.dateToStringWithTime();
        sysUser.setCreateTime(dateTime);
        sysUser.setStatus(SysStatus.ON.value);
        sysUser.setSource(UserParams.SOURCE_SYSTEM.value);

        //2.添加角色用户的关联关系
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setRoleCode(simpleUserBO.getRoleCode());
        sysUserRole.setUsername(sysUser.getUsername());
        sysUserRoleMapper.insertSelective(sysUserRole);

        int affectCount = sysUserMapper.insertSelective(sysUser);

        //====== redis ======
        if (affectCount > 0) {
            // redis_role_user (添加用户)
            setRedisRoleUserToRedis(simpleUserBO.getRoleCode(), simpleUserBO.getUsername());
        }
        return affectCount;
    }

    /**
     * 切换用户角色或状态
     * @param username 用户名
     * @param roleCode 角色代码
     * @param status 用户状态
     * @return 数量
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int updateSysUserRoleStatus(String username, String roleCode, String status) {
        int affectCount = 0;
        //更新用户-角色关联关系
        Example example = new Example(SysUserRole.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", username);

        //查询原始数据
        SysUserReVO sysUserReVO = getSysUserAndRoleByUsername(username);

        boolean isEqual1 = sysUserReVO.getRoleCode().equals(roleCode);
        boolean isEqual2 = sysUserReVO.getStatus().equals(status);

        //判断角色有没有变化,若有变化则修改数据库
        if (!isEqual1) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleCode(roleCode);
            sysUserRoleMapper.updateByExampleSelective(sysUserRole, example);
        }

        //判断状态有没有变化，若有变化则修改数据库
        if (!isEqual2) {
            Example example1 = new Example(SysUser.class);
            Example.Criteria criteria1 = example1.createCriteria();
            criteria1.andEqualTo("username", username);
            SysUser sysUser = new SysUser();
            sysUser.setStatus(status);
            affectCount = sysUserMapper.updateByExampleSelective(sysUser, example1);
        }

        //====== redis ======
        //1.角色不变，状态变化
        if (isEqual1 && !isEqual2) {
            //on
            if (SysStatus.ON.value.equals(status)) {
                setRedisRoleUserToRedis(roleCode,username);
            }else{
            //off
                delRedisRoleUserFromRedis(roleCode,username);
            }
        } else if (!isEqual1 && isEqual2) {
        //2.角色变化，状态不变
            if (SysStatus.ON.value.equals(status)) {
                updateRedisRoleForUser(username, sysUserReVO.getRoleCode(), roleCode);
            }
        } else if (!isEqual1 && !isEqual2) {
        //3.角色变化，状态变化
            //on
            if (SysStatus.ON.value.equals(status)) {
                setRedisRoleUserToRedis(roleCode,username);
            }else{
                //off
                delRedisRoleUserFromRedis(sysUserReVO.getRoleCode(),username);
            }
        }
        return affectCount;
    }

    /**
     * 删除用户信息
     * @param username 用户名
     * @return 数量
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int deleteSysUserByUsername(String username) {
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", username);

        //查询原始数据
        SysUserReVO sysUserReVO = getSysUserAndRoleByUsername(username);

        //删除用户-角色关联关系
        Example example1 = new Example(SysUserRole.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo("username", username);
        sysUserRoleMapper.deleteByExample(example1);
        int affectCount = sysUserMapper.deleteByExample(example);

        //====== redis ======
        if (affectCount > 0) {
            //删除 redis_role_user (可用角色-可用用户)
            if (SysStatus.ON.value.equals(sysUserReVO.getStatus())) {
                delRedisRoleUserFromRedis(sysUserReVO.getRoleCode(),username);
            }
            //删除 redis_user_token (用户登录信息)
            delRedisUserTokenFromRedis(username);
        }
        return affectCount;
    }

    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    @Override
    public PagedGridResult getOnlineUserByPage(Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        Set<String> keys = redisOperator.keys(UserParams.REDIS_USER_TOKEN.value+":*");
        List<String> list = new ArrayList<>();
        for (String key : keys) {
            String onlineUser = key.replace(UserParams.REDIS_USER_TOKEN.value + ":", "");
            list.add(onlineUser);
        }
        List<SysUserOnlineVO> sysUserOnlineVOList = sysUserMapperCustom.getOnlineUser(list);

        return setterPagedGrid(sysUserOnlineVOList,page);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public int updateMyUserInfo(SysUserBasicInfoBO basicInfoBO) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(basicInfoBO, sysUser, "username");
        Example example = new Example(SysUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("username", basicInfoBO.getUsername());
        return sysUserMapper.updateByExampleSelective(sysUser, example);
    }



    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
    @Override
    public SysSimpleUserVO getMySimpleUserInfo(String username) {
        return sysUserMapperCustom.getMySimpleUserInfo(username);
    }


}
